package com.yizisu.basemvvm.utils

import kotlinx.coroutines.*
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext

//yield()函数，让出执行权
/**
 * 创建一个协程作用域
 * context去下面的四个值中的一个
 * Dispatchers.IO 工作线程池，依赖于Dispatchers.Default，支持最大并行任务数。
 * Dispatchers.Unconfined 无指定派发线程，会根据运行时的上线文环境决定。
 * Dispatchers.Main 主线程，这个在不同平台定义不一样，所以需要引入相关的依赖，比如Android平台，需要使用包含MainLooper的handler来向主线程派发。
 * Dispatchers.Default 默认线程池，核心线程和最大线程数依赖cpu数量。
 * Dispatchers.IO：工作线程池，依赖于Dispatchers.Default，支持最大并行任务数。
 */
fun createCoroutine(): CoroutineScope {
    return CoroutineScope(EmptyCoroutineContext)
}

/**
 * 启动一个协程作用域，并且在子线程运行
 * 创建一个协程
 * DEFAULT	默认的模式，立即执行协程体
 * LAZY	只有在需要的情况下运行
 * ATOMIC	立即执行协程体，但在开始运行之前无法取消
 * UNDISPATCHED	立即在当前线程执行协程体，直到第一个 suspend 调用
 */
fun launchThread(
        start: CoroutineStart = CoroutineStart.DEFAULT,
        block: suspend CoroutineScope.() -> Unit
): Job {
    return createCoroutine().launch(Dispatchers.IO, start = start, block = block)
}

/**
 * 启动一个协程作用域，并且在子线程运行
 * 创建一个协程
 */
fun <T> asyncThread(
        start: CoroutineStart = CoroutineStart.DEFAULT,
        block: suspend CoroutineScope.() -> T
): Deferred<T> {
    return createCoroutine().async(Dispatchers.IO, start = start, block = block)
}

/**
 * 启动一个协程作用域，并且在主线程运行
 * 创建一个协程
 */
fun launchUi(
        start: CoroutineStart = CoroutineStart.DEFAULT,
        block: suspend CoroutineScope.() -> Unit
): Job {
    return createCoroutine().launch(Dispatchers.Main, start = start, block = block)
}

/**
 * 启动一个协程作用域，并且在主线程运行
 * 创建一个协程
 */
fun <T> asyncUi(
        start: CoroutineStart = CoroutineStart.DEFAULT,
        block: suspend CoroutineScope.() -> T
): Deferred<T> {
    return createCoroutine().async(Dispatchers.Main, start = start, block = block)
}

/**
 * 切换到主线程
 * 不创建新的协程
 */
suspend fun <T> switchToUi(block: suspend CoroutineScope.() -> T): T {
    return withContext(Dispatchers.Main, block)
}

/**
 * 切换到子线程
 * 不创建新的协程
 */
suspend fun <T> switchToThread(block: suspend CoroutineScope.() -> T): T {
    return withContext(Dispatchers.IO, block)
}

/**
 * 启动新的协程，代码运行在主线程
 * 没有自定义返回值
 * launch和async区别，一个有返回值，一个没有
 * start可以指定执行时机
 * async是可控的（await()阻塞当前协程，不往下执行。
 *                在定义的时候async已经开始运行了，
 *                await()只是等待执行完毕再向下执行，否则会继续走下面的逻辑）
 */
fun CoroutineScope.launchOnUi(
        start: CoroutineStart = CoroutineStart.DEFAULT,
        block: suspend CoroutineScope.() -> Unit
): Job {
    return launch(Dispatchers.Main, start = start, block = block)
}


/**
 * 启动新的协程，代码运行在主线程
 * 有自定义返回值
 *  start可以指定执行时机
 *  launch和async区别，一个有返回值，一个没有
 * async是可控的（await()阻塞当前协程，不往下执行。
 *                在定义的时候async已经开始运行了，
 *                await()只是等待执行完毕再向下执行，否则会继续走下面的逻辑）
 */
fun <T> CoroutineScope.asyncOnUi(
        start: CoroutineStart = CoroutineStart.DEFAULT,
        block: suspend CoroutineScope.() -> T
): Deferred<T> {
    return async(Dispatchers.Main, start = start, block = block)
}

/**
 * 启动新的协程，代码运行在子线程
 * 没有自定义返回值
 *  start可以指定执行时机
 *  launch和async区别，一个有返回值，一个没有
 * async是可控的（await()阻塞当前协程，不往下执行。
 *                在定义的时候async已经开始运行了，
 *                await()只是等待执行完毕再向下执行，否则会继续走下面的逻辑）
 */
fun CoroutineScope.launchOnThread(
        start: CoroutineStart = CoroutineStart.DEFAULT,
        block: suspend CoroutineScope.() -> Unit
): Job {
    return launch(Dispatchers.IO, start = start, block = block)
}

/**
 * 启动新的协程，代码运行在子线程
 * 有自定义返回值
 *  start可以指定执行时机
 *  launch和async区别，一个有返回值，一个没有
 * async是可控的（await()阻塞当前协程，不往下执行。
 *                在定义的时候async已经开始运行了，
 *                await()只是等待执行完毕再向下执行，否则会继续走下面的逻辑）
 */
fun <T> CoroutineScope.asyncOnThread(
        start: CoroutineStart = CoroutineStart.DEFAULT,
        block: suspend CoroutineScope.() -> T
): Deferred<T> {
    return async(Dispatchers.IO, start = start, block = block)
}
/*************************************列子**************************/
/**
 * switchToXx的使用
 * 按照顺序执行
 * 1-2-3-4-5-6-7-8
 */
private fun test1() {
    launchThread {
        val timeS = System.currentTimeMillis()
        val s1 = switchToThread {
            println("1")
            delay(1000)
            println("2")
            100
            switchToThread {
                println("3")
                delay(1000)
                println("4")
                110
            }
        }
        val s2 = switchToThread {
            println("5")
            delay(1000)
            println("6")
            100
        }
        println("7:${s1},${s2},${System.currentTimeMillis() - timeS}")
    }
}

/**
 * println打印函数不会等待s1 和s2执行完毕才执行，会优先执行
 */
private fun test2() {
    launchThread {
        val timeS = System.currentTimeMillis()
        val s1 = launch {
            println("1")
            delay(1000)
            println("")
        }
        val s2 = launch {
            println("2")
            delay(1000)
            println("")
            100
        }
        println("3:${s1},${s2},${System.currentTimeMillis() - timeS}")
    }
}